/**
 * 基于html5的websocket链接工具
 */
export default class WebSocketCreator {
  /**
   * 构造函数
   * @param {*} opts 配置参数
   * opts配置对象包括以下配置项：
   * websocketUrl： websocket url
   * websocketProtocol：websocket 协议，和后端约定的协议规则
   * heartbeatContent：心跳包的内容
   * heartbeatCheckable：是否开启心跳检测机制
   * onclose：当websocket被关闭
   * onerror：当websocket异常
   * onopen：当websocket链接打开
   * onmessage：当websocket消息到达
   */
  constructor(opts) {
    this.options = {
      websocketUrl: null,
      websocketProtocol: null,
      heartbeatContent: "heartbeat",
      heartbeatCheckable: true,
      onclose: null,
      onerror: null,
      onopen: null,
      onmessage: null,
    };
    for (const type in this.options) {
      if (Object.prototype.hasOwnProperty.call(this.options, type)) {
        if (opts[type]) {
          this.options[type] = opts[type];
        }
      }
    }

    // 心跳检测机制
    this.heartbeatCheck = {
      timeout: 3000,
      timeoutObj: null,
      serverTimeoutObj: null,
      start: function (ws, heartbeatContent) {
        this.timeoutObj && clearTimeout(this.timeoutObj);
        this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
        this.timeoutObj = setTimeout(() => {
          // 这里发送一个心跳，后端收到后，返回一个心跳消息，
          ws.send(heartbeatContent);
          this.serverTimeoutObj = setTimeout(function () {
            ws.close();
          }, this.timeout);
        }, this.timeout);
      },
      stop() {
        this.timeoutObj && clearTimeout(this.timeoutObj);
        this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
      },
    };
    this.isHandleStop = false;
    this.createWebSocket();
  }

  /**
   * 创建websocket
   */
  createWebSocket() {
    // 如果已经被手动关闭，则不新建websocket
    if (this.isHandleStop) {
      return;
    }
    try {
      const WebsocketCtl = window["MozWebSocket"]
        ? window["MozWebSocket"]
        : WebSocket;
      if (!this.options.websocketProtocol) {
        this.ws = new WebsocketCtl(this.options.websocketUrl);
      } else {
        this.ws = new WebsocketCtl(
          this.options.websocketUrl,
          this.options.websocketProtocol
        );
      }

      this.initEvent();
    } catch (e) {
      this.reconnect();
    }
  }

  /**
   * 初始化事件处理
   */
  initEvent() {
    this.ws.onclose = () => {
      this.reconnect();
      if (this.options.onclose && typeof this.options.onclose === "function") {
        this.options.onclose();
      }
    };
    this.ws.onerror = () => {
      this.reconnect();
      if (this.options.onerror && typeof this.options.onerror === "function") {
        this.options.onerror();
      }
    };
    this.ws.onopen = () => {
      // 心跳检测重置
      if (this.options.heartbeatCheckable) {
        this.heartbeatCheck.start(this.ws, this.options.heartbeatContent);
      }

      if (this.options.onopen && typeof this.options.onopen === "function") {
        this.options.onopen();
      }
    };
    this.ws.onmessage = (event) => {
      // 收到消息说明当前连接正常
      // 启动心跳检测
      if (this.options.heartbeatCheckable) {
        this.heartbeatCheck.start(this.ws, this.options.heartbeatContent);
      }
      if (
        this.options.onmessage &&
        typeof this.options.onmessage === "function"
      ) {
        this.options.onmessage(event);
      }
    };
  }

  /**
   * 重连
   * @returns
   */
  reconnect() {
    // 正在重连，则取消重连请求
    if (this.isConnectting) {
      return;
    }
    this.isConnectting = true;
    this.reconnectTimeout && clearTimeout(this.reconnectTimeout);
    this.reconnectTimeout = setTimeout(() => {
      this.createWebSocket();
      this.isConnectting = false;
    }, 4000);
  }

  /**
   * 发送消息
   * @param {*} msg
   */
  send(msg) {
    if (!this.ws) {
      return;
    }
    this.ws.send(msg);
  }

  /**
   * 主动关闭websocket
   */
  stopWebsocket() {
    this.isHandleStop = true;
    this.options.heartbeatCheckable = false;
    // this.ws.close();
    this.heartbeatCheck.stop();
  }
}
